package cn.wildfirechat.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.YearMonth;
import java.util.List;

@Component
public class LoginLogPartitionScheduler {
    private static final Logger LOG = LoggerFactory.getLogger(LoginLogPartitionScheduler.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Scheduled(cron = "0 0 2 1 * ?", zone = "Asia/Shanghai")
    public void maintainLoginLogPartitions() {
        tryInitPartitioning();
        addNextMonthPartitionIfMissing();
        cleanupOldPartitions();
    }

    private void tryInitPartitioning() {
        try {
            jdbcTemplate.execute("CALL direct_partition_app_login_log(6)");
        } catch (Exception e) {
            LOG.debug("direct_partition_app_login_log not available or failed: {}", e.getMessage());
        }
    }

    private void addNextMonthPartitionIfMissing() {
        YearMonth next = YearMonth.now().plusMonths(1);
        String partName = "p" + next.toString().replace("-", "");
        Integer cnt = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM information_schema.partitions WHERE table_schema = DATABASE() AND table_name = 'app_login_log' AND partition_name = ?",
                Integer.class,
                partName
        );
        if (cnt != null && cnt == 0) {
            LocalDate nextFirst = next.atDay(1);
            String sql = "ALTER TABLE app_login_log REORGANIZE PARTITION pMAX INTO (" +
                    "PARTITION " + partName + " VALUES LESS THAN (TO_DAYS('" + nextFirst + "')), " +
                    "PARTITION pMAX VALUES LESS THAN MAXVALUE)";
            try {
                jdbcTemplate.execute(sql);
                LOG.info("Added partition {}", partName);
            } catch (Exception e) {
                LOG.warn("Add next month partition failed: {}", e.getMessage());
            }
        }
    }

    private void cleanupOldPartitions() {
        YearMonth cutoffYm = YearMonth.now().minusMonths(6);
        LocalDate cutoff = cutoffYm.atDay(1);
        List<String> parts = jdbcTemplate.query(
                "SELECT partition_name FROM information_schema.partitions " +
                        "WHERE table_schema = DATABASE() AND table_name = 'app_login_log' " +
                        "AND partition_name IS NOT NULL AND partition_name <> 'pMAX' " +
                        "AND partition_description < TO_DAYS(?)",
                (rs, i) -> rs.getString(1),
                cutoff.toString()
        );
        for (String p : parts) {
            try {
                jdbcTemplate.execute("ALTER TABLE app_login_log DROP PARTITION " + p);
                LOG.info("Dropped old partition {}", p);
            } catch (Exception e) {
                LOG.warn("Drop partition {} failed: {}", p, e.getMessage());
            }
        }
    }
}